Skip to content

Method: createNativeQuery(String, String)

1: /**
2: * Copyright (C) 2020 Czech Technical University in Prague
3: *
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: *
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.model;
16:
17: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
18: import cz.cvut.kbss.jopa.exceptions.TransactionRequiredException;
19: import cz.cvut.kbss.jopa.model.annotations.CascadeType;
20: import cz.cvut.kbss.jopa.model.descriptors.Descriptor;
21: import cz.cvut.kbss.jopa.model.descriptors.EntityDescriptor;
22: import cz.cvut.kbss.jopa.model.metamodel.Attribute;
23: import cz.cvut.kbss.jopa.model.metamodel.Metamodel;
24: import cz.cvut.kbss.jopa.sessions.ServerSession;
25: import cz.cvut.kbss.jopa.sessions.UnitOfWorkImpl;
26: import cz.cvut.kbss.jopa.transactions.EntityTransaction;
27: import cz.cvut.kbss.jopa.transactions.EntityTransactionWrapper;
28: import cz.cvut.kbss.jopa.transactions.TransactionWrapper;
29: import cz.cvut.kbss.jopa.utils.*;
30: import org.slf4j.Logger;
31: import org.slf4j.LoggerFactory;
32:
33: import java.net.URI;
34: import java.util.*;
35:
36: public class EntityManagerImpl implements AbstractEntityManager, Wrapper {
37:
38: private static final Logger LOG = LoggerFactory.getLogger(EntityManagerImpl.class);
39:
40: private static final Object MAP_VALUE = new Object();
41:
42: private EntityManagerFactoryImpl emf;
43:
44: private boolean open;
45:
46: private TransactionWrapper transaction;
47: private UnitOfWorkImpl persistenceContext;
48: private ServerSession serverSession;
49: private final Configuration configuration;
50:
51: private Map<Object, Object> cascadingRegistry = new IdentityHashMap<>();
52:
53: EntityManagerImpl(EntityManagerFactoryImpl emf, Configuration configuration, ServerSession serverSession) {
54: this.emf = emf;
55: this.serverSession = serverSession;
56: this.configuration = configuration;
57:
58: setTransactionWrapper();
59:
60: this.open = true;
61: }
62:
63: public enum State {
64: MANAGED, MANAGED_NEW, NOT_MANAGED, REMOVED
65: }
66:
67: @Override
68: public void persist(final Object entity) {
69: final Descriptor d = new EntityDescriptor();
70: persist(entity, d);
71: }
72:
73: @Override
74: public void persist(final Object entity, final Descriptor descriptor) {
75: LOG.trace("Persisting instance of type {}.", entity.getClass());
76: try {
77: Objects.requireNonNull(entity, ErrorUtils.getNPXMessageSupplier("entity"));
78: Objects.requireNonNull(descriptor, ErrorUtils.getNPXMessageSupplier("descriptor"));
79: ensureOpen();
80: checkClassIsValidEntity(entity.getClass());
81:
82: switch (getState(entity, descriptor)) {
83: case NOT_MANAGED:
84: getCurrentPersistenceContext().registerNewObject(entity, descriptor);
85: // Intentional fall-through
86: case MANAGED:
87: cascadePersist(entity, descriptor);
88: break;
89: case REMOVED:
90: getCurrentPersistenceContext().restoreRemovedObject(entity);
91: break;
92: default:
93: break;
94: }
95: } catch (RuntimeException e) {
96: markTransactionForRollback();
97: throw e;
98: }
99: }
100:
101: private void checkClassIsValidEntity(Class<?> cls) {
102: getMetamodel().entity(cls);
103: }
104:
105: private void registerProcessedInstance(Object instance) {
106: cascadingRegistry.put(instance, MAP_VALUE);
107: }
108:
109: private boolean isCascadingCycle(Object instance) {
110: return cascadingRegistry.containsKey(instance);
111: }
112:
113: private void resetCascadingRegistry() {
114: cascadingRegistry.clear();
115: }
116:
117: private void markTransactionForRollback() {
118: if (getTransaction().isActive()) {
119: getTransaction().setRollbackOnly();
120: }
121: }
122:
123: private void cascadePersist(final Object entity, final Descriptor descriptor) {
124: new OneLevelCascadeExplorer() {
125: @Override
126: protected void exploreCascaded(Attribute<?, ?> at, Object o) {
127: try {
128: Object ox = EntityPropertiesUtils.getAttributeValue(at, o);
129: LOG.trace("object={}, attribute={}, value={}", o, at.getName(), ox);
130: if (ox == null) {
131: return;
132: }
133: final Descriptor attDescriptor = descriptor.getAttributeDescriptor(at);
134: if (at.isCollection()) {
135: for (final Object ox2 : (Collection<?>) ox) {
136: persist(ox2, attDescriptor);
137: }
138: } else {
139: persist(ox, attDescriptor);
140: }
141: } catch (Exception e) {
142: markTransactionForRollback();
143: throw new OWLPersistenceException(
144: "A problem occurred when persisting attribute " + at.getName()
145: + " of with value " + o + " of object " + entity, e);
146: }
147: }
148: }.start(this, entity, CascadeType.PERSIST);
149: }
150:
151: @Override
152: public <T> T merge(final T entity) {
153: final Descriptor d = new EntityDescriptor();
154: return merge(entity, d);
155: }
156:
157: @Override
158: public <T> T merge(final T entity, final Descriptor descriptor) {
159: try {
160: Objects.requireNonNull(entity, ErrorUtils.getNPXMessageSupplier("entity"));
161: Objects.requireNonNull(descriptor, ErrorUtils.getNPXMessageSupplier("descriptor"));
162: ensureOpen();
163: checkClassIsValidEntity(entity.getClass());
164:
165: return mergeInternal(entity, descriptor);
166: } catch (RuntimeException e) {
167: markTransactionForRollback();
168: throw e;
169: } finally {
170: resetCascadingRegistry();
171: }
172: }
173:
174: /**
175: * Merges state of the specified entity into the current persistence context. </p>
176: *
177: * @param entity Entity instance
178: * @param descriptor Contains information about contexts into which the entity and its field should be merged
179: * @return Managed instance of the merged entity
180: */
181: private <T> T mergeInternal(final T entity, final Descriptor descriptor) {
182: assert entity != null;
183: assert descriptor != null;
184: LOG.trace("Merging instance of type {}.", entity.getClass());
185: if (isCascadingCycle(entity)) {
186: LOG.warn("Merge cascading cycle detected in entity {}.", entity);
187: return (T) getCurrentPersistenceContext().getCloneForOriginal(entity);
188: }
189:
190: switch (getState(entity, descriptor)) {
191: case MANAGED_NEW:
192: case MANAGED:
193: registerProcessedInstance(entity);
194: cascadeMerge(entity, entity, descriptor);
195: return entity;
196: case NOT_MANAGED:
197: final T merged = getCurrentPersistenceContext().mergeDetached(entity, descriptor);
198: registerProcessedInstance(entity);
199: cascadeMerge(merged, entity, descriptor);
200: return merged;
201: case REMOVED:
202: default:
203: throw new IllegalArgumentException("Cannot merge instance which is not an entity or is removed.");
204: }
205: }
206:
207: private <T> void cascadeMerge(T merged, T toMerge, Descriptor descriptor) {
208: new OneLevelMergeCascadeExplorer() {
209: @Override
210: protected void exploreCascaded(Attribute<?, ?> at, Object merged, Object toMerge) {
211: final Descriptor attDescriptor = descriptor.getAttributeDescriptor(at);
212: mergeX(at, merged, toMerge, attDescriptor);
213: }
214: }.start(this, merged, toMerge);
215: }
216:
217: private void mergeX(Attribute<?, ?> at, Object merged, Object toMerge, Descriptor descriptor) {
218: Object attVal = EntityPropertiesUtils.getAttributeValue(at, toMerge);
219: if (attVal == null) {
220: return;
221: }
222: if (at.isCollection()) {
223: Collection c = (Collection) attVal;
224: Collection result = CollectionFactory.createInstance(c);
225: for (final Object ox2 : c) {
226: result.add(mergeInternal(ox2, descriptor));
227: }
228: attVal = getCurrentPersistenceContext().createIndirectCollection(result, merged, at.getJavaField());
229: } else {
230: attVal = mergeInternal(attVal, descriptor);
231: }
232: EntityPropertiesUtils.setFieldValue(at.getJavaField(), merged, attVal);
233: }
234:
235: @Override
236: public void remove(Object object) {
237: try {
238: ensureOpen();
239: Objects.requireNonNull(object);
240: checkClassIsValidEntity(object.getClass());
241: if (isCascadingCycle(object)) {
242: LOG.warn("Remove cascading cycle detected in instance {}.", object);
243: return;
244: }
245:
246: switch (getState(object)) {
247: case MANAGED_NEW:
248: case MANAGED:
249: getCurrentPersistenceContext().removeObject(object);
250: registerProcessedInstance(object);
251: // Intentional fall-through
252: case REMOVED:
253: new SimpleOneLevelCascadeExplorer() {
254: @Override
255: protected void runCascadedForEach(Object ox2) {
256: remove(ox2);
257: }
258: }.start(this, object, CascadeType.REMOVE);
259: break;
260: default:
261: throw new IllegalArgumentException("Entity " + object + " is not managed and cannot be removed.");
262: }
263: } catch (RuntimeException e) {
264: markTransactionForRollback();
265: throw e;
266: } finally {
267: resetCascadingRegistry();
268: }
269: }
270:
271: @Override
272: public <T> T find(Class<T> cls, Object identifier) {
273: final EntityDescriptor d = new EntityDescriptor();
274: return find(cls, identifier, d);
275: }
276:
277: @Override
278: public <T> T find(Class<T> cls, Object identifier, Descriptor descriptor) {
279: try {
280: Objects.requireNonNull(cls, ErrorUtils.getNPXMessageSupplier("cls"));
281: Objects.requireNonNull(identifier, ErrorUtils.getNPXMessageSupplier("primaryKey"));
282: Objects.requireNonNull(descriptor, ErrorUtils.getNPXMessageSupplier("descriptor"));
283: ensureOpen();
284: checkClassIsValidEntity(cls);
285:
286: LOG.trace("Finding instance of {} with identifier {} in context {}.", cls, identifier, descriptor);
287: final URI uri = (identifier instanceof URI) ? (URI) identifier : URI.create(identifier.toString());
288:
289: return getCurrentPersistenceContext().readObject(cls, uri, descriptor);
290: } catch (RuntimeException e) {
291: markTransactionForRollback();
292: throw e;
293: }
294: }
295:
296: @Override
297: public <T> T getReference(Class<T> entityClass, Object identifier) {
298: try {
299: Objects.requireNonNull(entityClass);
300: Objects.requireNonNull(identifier);
301:
302: return getReference(entityClass, identifier, new EntityDescriptor());
303: } catch (RuntimeException e) {
304: markTransactionForRollback();
305: throw e;
306: }
307: }
308:
309: @Override
310: public <T> T getReference(Class<T> entityClass, Object identifier, Descriptor descriptor) {
311: try {
312: Objects.requireNonNull(entityClass);
313: Objects.requireNonNull(identifier);
314: Objects.requireNonNull(descriptor);
315: ensureOpen();
316: checkClassIsValidEntity(entityClass);
317:
318: LOG.trace("Getting reference of type {} with identifier {} in context {}.", entityClass, identifier,
319: descriptor);
320: return getCurrentPersistenceContext().getReference(entityClass, identifier, descriptor);
321: } catch (RuntimeException e) {
322: markTransactionForRollback();
323: throw e;
324: }
325: }
326:
327: @Override
328: public void flush() {
329: try {
330: ensureOpen();
331: LOG.trace("Flushing changes...");
332: if (!getTransaction().isActive()) {
333: throw new TransactionRequiredException("Cannot flush entity manager outside of a transaction.");
334: }
335: this.getCurrentPersistenceContext().writeUncommittedChanges();
336: } catch (RuntimeException e) {
337: markTransactionForRollback();
338: throw e;
339: }
340: }
341:
342: @Override
343: public void refresh(Object entity) {
344: try {
345: ensureOpen();
346: Objects.requireNonNull(entity);
347: checkClassIsValidEntity(entity.getClass());
348:
349: this.getCurrentPersistenceContext().refreshObject(entity);
350: new SimpleOneLevelCascadeExplorer() {
351: @Override
352: protected void runCascadedForEach(Object ox2) {
353: refresh(ox2);
354: }
355: }.start(this, entity, CascadeType.REFRESH);
356: } catch (RuntimeException e) {
357: markTransactionForRollback();
358: throw e;
359: }
360: }
361:
362: @Override
363: public void clear() {
364: try {
365: ensureOpen();
366: getCurrentPersistenceContext().clear();
367: } catch (RuntimeException e) {
368: markTransactionForRollback();
369: throw e;
370: }
371: }
372:
373: @Override
374: public void detach(Object entity) {
375: try {
376: ensureOpen();
377:
378: switch (getState(entity)) {
379: case MANAGED_NEW:
380: case MANAGED:
381: getCurrentPersistenceContext().unregisterObject(entity);
382: new SimpleOneLevelCascadeExplorer() {
383: @Override
384: protected void runCascadedForEach(Object ox2) {
385: detach(ox2);
386: }
387: }.start(this, entity, CascadeType.DETACH);
388: break;
389: default:
390: break;
391: }
392: } catch (RuntimeException e) {
393: markTransactionForRollback();
394: throw e;
395: }
396: }
397:
398: @Override
399: public boolean contains(Object entity) {
400: try {
401: ensureOpen();
402: Objects.requireNonNull(entity);
403: checkClassIsValidEntity(entity.getClass());
404: return getCurrentPersistenceContext().contains(entity);
405: } catch (RuntimeException e) {
406: markTransactionForRollback();
407: throw e;
408: }
409: }
410:
411: @Override
412: public void close() {
413: ensureOpen();
414: removeCurrentPersistenceContext();
415: this.cascadingRegistry = null;
416: emf.entityManagerClosed(this);
417: this.open = false;
418: }
419:
420: @Override
421: public boolean isOpen() {
422: return open;
423: }
424:
425: @Override
426: public EntityTransaction getTransaction() {
427: return transaction.getTransaction();
428: }
429:
430: @Override
431: public EntityManagerFactoryImpl getEntityManagerFactory() {
432: return emf;
433: }
434:
435: @Override
436: public Metamodel getMetamodel() {
437: return emf.getMetamodel();
438: }
439:
440: @Override
441: public boolean isLoaded(final Object object, final String attributeName) {
442: Objects.requireNonNull(object);
443: Objects.requireNonNull(attributeName);
444: return getCurrentPersistenceContext().isLoaded(object, attributeName) == LoadState.LOADED;
445: }
446:
447: @Override
448: public boolean isLoaded(Object object) {
449: return getCurrentPersistenceContext().isLoaded(object) == LoadState.LOADED;
450: }
451:
452: @Override
453: public QueryImpl createQuery(String qlString) {
454: ensureOpen();
455: final QueryImpl q = getCurrentPersistenceContext().sparqlQueryFactory().createQuery(qlString);
456: q.setRollbackOnlyMarker(this::markTransactionForRollback);
457: q.setEnsureOpenProcedure(this::ensureOpen);
458: return q;
459: }
460:
461: @Override
462: public <T> TypedQueryImpl<T> createQuery(String query, Class<T> resultClass) {
463: ensureOpen();
464: final TypedQueryImpl<T> q = getCurrentPersistenceContext().sparqlQueryFactory().createQuery(query, resultClass);
465: q.setRollbackOnlyMarker(this::markTransactionForRollback);
466: q.setEnsureOpenProcedure(this::ensureOpen);
467: return q;
468: }
469:
470: @Override
471: public QueryImpl createNativeQuery(String sparqlString) {
472: ensureOpen();
473: final QueryImpl q = getCurrentPersistenceContext().sparqlQueryFactory().createNativeQuery(sparqlString);
474: q.setRollbackOnlyMarker(this::markTransactionForRollback);
475: q.setEnsureOpenProcedure(this::ensureOpen);
476: return q;
477: }
478:
479: @Override
480: public <T> TypedQueryImpl<T> createNativeQuery(String sparqlString, Class<T> resultClass) {
481: ensureOpen();
482: final TypedQueryImpl<T> q = getCurrentPersistenceContext().sparqlQueryFactory()
483: .createNativeQuery(sparqlString, resultClass);
484: q.setRollbackOnlyMarker(this::markTransactionForRollback);
485: q.setEnsureOpenProcedure(this::ensureOpen);
486: return q;
487: }
488:
489: @Override
490: public QueryImpl createNativeQuery(String sparqlString, String resultSetMapping) {
491: ensureOpen();
492: final QueryImpl q = getCurrentPersistenceContext().sparqlQueryFactory()
493: .createNativeQuery(sparqlString, resultSetMapping);
494: q.setRollbackOnlyMarker(this::markTransactionForRollback);
495: q.setEnsureOpenProcedure(this::ensureOpen);
496: return q;
497: }
498:
499: @Override
500: public QueryImpl createNamedQuery(String name) {
501: ensureOpen();
502: final QueryImpl q = getCurrentPersistenceContext().sparqlQueryFactory().createNamedQuery(name);
503: q.setRollbackOnlyMarker(this::markTransactionForRollback);
504: q.setEnsureOpenProcedure(this::ensureOpen);
505: return q;
506: }
507:
508: @Override
509: public <T> TypedQueryImpl<T> createNamedQuery(String name, Class<T> resultClass) {
510: ensureOpen();
511: final TypedQueryImpl<T> q = getCurrentPersistenceContext().sparqlQueryFactory()
512: .createNamedQuery(name, resultClass);
513: q.setRollbackOnlyMarker(this::markTransactionForRollback);
514: q.setEnsureOpenProcedure(this::ensureOpen);
515: return q;
516: }
517:
518: @Override
519: public boolean isConsistent(URI context) {
520: ensureOpen();
521: return getCurrentPersistenceContext().isConsistent(context);
522: }
523:
524: @Override
525: public List<URI> getContexts() {
526: ensureOpen();
527: return getCurrentPersistenceContext().getContexts();
528: }
529:
530: @Override
531: public void setUseTransactionalOntologyForQueryProcessing() {
532: ensureOpen();
533: getCurrentPersistenceContext().setUseTransactionalOntologyForQueryProcessing();
534: }
535:
536: @Override
537: public boolean useTransactionalOntologyForQueryProcessing() {
538: ensureOpen();
539: return getCurrentPersistenceContext().useTransactionalOntologyForQueryProcessing();
540: }
541:
542: @Override
543: public void setUseBackupOntologyForQueryProcessing() {
544: ensureOpen();
545: getCurrentPersistenceContext().setUseBackupOntologyForQueryProcessing();
546: }
547:
548: @Override
549: public boolean useBackupOntologyForQueryProcessing() {
550: ensureOpen();
551: return getCurrentPersistenceContext().useBackupOntologyForQueryProcessing();
552: }
553:
554: @Override
555: public <T> T unwrap(Class<T> cls) {
556: ensureOpen();
557: if (cls.isAssignableFrom(this.getClass())) {
558: return cls.cast(this);
559: }
560: return getCurrentPersistenceContext().unwrap(cls);
561: }
562:
563: @Override
564: public Object getDelegate() {
565: return unwrap(EntityManagerImpl.class);
566: }
567:
568: private void ensureOpen() {
569: if (!isOpen()) {
570: throw new IllegalStateException("The entity manager is closed !");
571: }
572: }
573:
574: private State getState(Object entity) {
575: return getCurrentPersistenceContext().getState(entity);
576: }
577:
578: private State getState(Object entity, Descriptor descriptor) {
579: return getCurrentPersistenceContext().getState(entity, descriptor);
580: }
581:
582: @Override
583: protected void finalize() throws Throwable {
584: if (open) {
585: close();
586: }
587: super.finalize();
588: }
589:
590: @Override
591: public UnitOfWorkImpl getCurrentPersistenceContext() {
592: if (this.persistenceContext == null) {
593: this.persistenceContext = (UnitOfWorkImpl) serverSession.acquireUnitOfWork();
594: persistenceContext.setEntityManager(this);
595: }
596: return this.persistenceContext;
597: }
598:
599: /**
600: * Called from EntityTransaction in case of a rollback. Releasing the UoW is up to the EntityTransaction.
601: */
602: @Override
603: public void removeCurrentPersistenceContext() {
604: if (persistenceContext != null && persistenceContext.isActive()) {
605: persistenceContext.release();
606: }
607: this.persistenceContext = null;
608: }
609:
610: @Override
611: public void transactionStarted(EntityTransaction t) {
612: serverSession.transactionStarted(t, this);
613: }
614:
615: @Override
616: public void transactionFinished(EntityTransaction t) {
617: this.serverSession.transactionFinished(t);
618: }
619:
620: /**
621: * Since we support only EntityTransactions, we set the TransactionWrapper to EntityTransactionWrapper.
622: * <p>
623: * In the future, if JTA transactions are supported, JTATransactionWrapper should be set instead of the
624: * EntityTransactionWrapper.
625: */
626: private void setTransactionWrapper() {
627: this.transaction = new EntityTransactionWrapper(this);
628: }
629:
630: @Override
631: public Configuration getConfiguration() {
632: return configuration;
633: }
634: }